package com.hyacinth.utils;

import com.hyacinth.utils.exception.UtilException;

import java.math.BigDecimal;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * 数字工具类
 * @author zhaorq
 * @version 1.0.0.1
 */
public final class NumberUtils {
	
	/** 0金额:0.00 */
	public static BigDecimal MONEY_ZERO = new BigDecimal("0.00");

	/**
	 * 解析转换数字字符串为int型数字，规则如下：
	 *
	 * <pre>
	 * 1、0x开头的视为16进制数字
	 * 2、0开头的视为8进制数字
	 * 3、其它情况按照10进制转换
	 * 4、空串返回0
	 * 5、.123形式返回0（按照小于0的小数对待）
	 * 6、123.56截取小数点之前的数字，忽略小数部分
	 * </pre>
	 *
	 * @param number 数字，支持0x开头、0开头和普通十进制
	 * @return int
	 * @throws NumberFormatException 数字格式异常
	 * @since 4.1.4
	 */
	public static int parseInt(String number) throws NumberFormatException {
		if (StringUtils.isBlank(number)) {
			return 0;
		}

		// 对于带小数转换为整数采取去掉小数的策略
		number = StringUtils.substringBefore(number, StringUtils.DOT);
		if (StringUtils.isEmpty(number)) {
			return 0;
		}

		if (StringUtils.startsWithIgnoreCase(number, "0x")) {
			// 0x04表示16进制数
			return Integer.parseInt(number.substring(2), 16);
		}

		return Integer.parseInt(removeNumberFlag(number));
	}

	/**
	 * 解析转换数字字符串为long型数字，规则如下：
	 *
	 * <pre>
	 * 1、0x开头的视为16进制数字
	 * 2、0开头的视为8进制数字
	 * 3、空串返回0
	 * 4、其它情况按照10进制转换
	 * </pre>
	 *
	 * @param number 数字，支持0x开头、0开头和普通十进制
	 * @return long
	 * @since 4.1.4
	 */
	public static long parseLong(String number) {
		if (StringUtils.isBlank(number)) {
			return 0;
		}

		// 对于带小数转换为整数采取去掉小数的策略
		number = StringUtils.substringBefore(number, StringUtils.DOT);
		if (StringUtils.isEmpty(number)) {
			return 0;
		}

		if (number.startsWith("0x")) {
			// 0x04表示16进制数
			return Long.parseLong(number.substring(2), 16);
		}

		return Long.parseLong(removeNumberFlag(number));
	}

	/**
	 * 将指定字符串转换为{@link Number} 对象
	 *
	 * @param numberStr Number字符串
	 * @return Number对象
	 * @since 4.1.15
	 */
	public static Number parseNumber(String numberStr) {
		numberStr = removeNumberFlag(numberStr);
		try {
			return NumberFormat.getInstance().parse(numberStr);
		} catch (ParseException e) {
			throw new UtilException(e);
		}
	}

	/**
	 * 去掉数字尾部的数字标识，例如12D，44.0F，22L中的最后一个字母
	 *
	 * @param number 数字字符串
	 * @return 去掉标识的字符串
	 */
	private static String removeNumberFlag(String number) {
		// 去掉类型标识的结尾
		final int lastPos = number.length() - 1;
		final char lastCharUpper = Character.toUpperCase(number.charAt(lastPos));
		if ('D' == lastCharUpper || 'L' == lastCharUpper || 'F' == lastCharUpper) {
			number = StringUtils.substring(number, 0, lastPos);
		}
		return number;
	}

	/**
	 * 是否为0
	 * @param value
	 * @return
	 */
	public static boolean isZero(Integer value) {
		if (value == null || value == 0) {
			return true;
		}
		return false;
	}

	/**
	 * 是否为正
	 * @param value
	 * @return
	 */
	public static boolean isPositive(Integer value) {
		if (value != null && value > 0) {
			return true;
		}
		return false;
	}

	/**
	 * 是否为负
	 * @param value
	 * @return
	 */
	public static boolean isNegative(Integer value) {
		if (value != null && value < 0) {
			return true;
		}
		return false;
	}

	/**
	 * 求和
	 * @return
	 */
	public static int sum(Integer... values) {
		int sum = 0;
		for (Integer val : values) {
			if (val != null) {
				sum += val;
			}
		}
		return sum;
	}

	/**
	 * 是否为0
	 * @param value
	 * @return
	 */
	public static boolean isZero(BigDecimal value) {
		if (value == null || value.compareTo(BigDecimal.ZERO) == 0) {
			return true;
		}
		return false;
	}

	/**
	 * 是否为正
	 * @param value
	 * @return
	 */
	public static boolean isPositive(BigDecimal value) {
		if (value != null && value.compareTo(BigDecimal.ZERO) > 0) {
			return true;
		}
		return false;
	}

	/**
	 * 是否为负
	 * @param value
	 * @return
	 */
	public static boolean isNegative(BigDecimal value) {
		if (value != null && value.compareTo(BigDecimal.ZERO) < 0) {
			return true;
		}
		return false;
	}

	/**
	 * 比较
	 * @param val
	 * @param val2
	 * @return
	 */
	public static int compareTo(BigDecimal val, BigDecimal val2) {
		if (val != null && val2 != null) {
			return val.compareTo(val2);
		}
		if (val != null && val2 == null) {
			return val.compareTo(BigDecimal.ZERO);
		}
		if (val == null && val2 != null) {
			return val2.compareTo(BigDecimal.ZERO);
		}
		return 0;
	}

	/**
	 * 是否相等
	 * @param val
	 * @param val2
	 * @return
	 */
	public static boolean isEquals(BigDecimal val, BigDecimal val2) {
		return compareTo(val, val2) == 0;
	}

	/**
	 * 相乘
	 * @param value
	 * @param multiplicand
	 * @param scale 精度
	 * @return
	 */
	public static BigDecimal multiply(BigDecimal value, int multiplicand, int scale) {
		return multiply(value, new BigDecimal(multiplicand), scale);
	}

	/**
	 * 相乘
	 * @param value
	 * @param multiplicand
	 * @param scale
	 * @return
	 */
	public static BigDecimal multiply(BigDecimal value, BigDecimal multiplicand, int scale) {
		return multiply(value, multiplicand, scale, BigDecimal.ROUND_HALF_UP);
	}
	
	/**
	 * 相乘
	 * @param value
	 * @param multiplicand
	 * @param scale
	 * @return
	 */
	public static BigDecimal multiply(BigDecimal value, BigDecimal multiplicand, int scale, int round) {
		if (isZero(value) || isZero(multiplicand)) {
			return BigDecimal.ZERO.setScale(scale);
		}
		return value.multiply(multiplicand).setScale(scale, round);
	}

	/**
	 * 相乘(带舍入模式)
	 * @param value
	 * @param multiplicand
	 * @param scale
	 * @param roundingMode
	 * @return
	 */
	public static BigDecimal multiply(BigDecimal value, int multiplicand, int scale, int roundingMode) {
		if (isZero(value) || isZero(multiplicand)) {
			return BigDecimal.ZERO.setScale(scale);
		}
		return value.multiply(new BigDecimal(multiplicand)).setScale(scale, roundingMode);
	}

	/**
	 * 相减
	 * @param value
	 * @param subtrahend
	 * @return
	 */
	public static BigDecimal subtract(BigDecimal value, BigDecimal subtrahend) {
		if (isZero(value)) {
			value = BigDecimal.ZERO;
		}
		if (isZero(subtrahend)) {
			return value;
		}
		return value.subtract(subtrahend);
	}

	/**
	 * 求和运算
	 * @param values 变参值
	 * @return
	 */
	public static BigDecimal sum(BigDecimal... values) {
		BigDecimal sum = BigDecimal.ZERO;
		for (BigDecimal val : values) {
			if (val != null) {
				sum = sum.add(val);
			}
		}
		return sum;
	}

	/**
	 * 依据字符串获取BigDecimal
	 * @param bigDecimalStr
	 * @return
	 */
	public static BigDecimal getBigDecimal(String bigDecimalStr) {
		try {
			return new BigDecimal(bigDecimalStr);
		} catch (Exception e) {
			return BigDecimal.ZERO;
		}
	}
	
	/**
	 * 格式化金额(大写)
	 * @param money
	 * @return
	 */
	public static String formatMoney(BigDecimal money) {
		String fraction[] = {"角", "分"};
        String digit[] = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" };
        String unit[][] = {{"元", "万", "亿"}, {"", "拾", "佰", "仟"}};
 
        String head = money.doubleValue() < 0? "负": "";
        int n = Math.abs(money.intValue());
        
        String s = "";
        for (int i = 0; i < fraction.length; i++) {
            s += (digit[(int)(Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
        }
        if(s.length()<1){
            s = "整";    
        }
        int integerPart = (int)Math.floor(n);
 
        for (int i = 0; i < unit[0].length && integerPart > 0; i++) {
            String p ="";
            for (int j = 0; j < unit[1].length && n > 0; j++) {
                p = digit[integerPart%10]+unit[1][j] + p;
                integerPart = integerPart/10;
            }
            s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s;
        }
        return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整");
    }

    /**
     * 获取map参数中参数并转化为BigDecimal
     * @param map
     * @param key
     * @return
     */
    public static BigDecimal getBigDecimal(Map<String,Object> map, String key) {
		try {
			return map.get(key) == null ? BigDecimal.ZERO : new BigDecimal(map.get(key).toString());
		} catch (Exception e) {
			return BigDecimal.ZERO;
		}
    }
    
    /**
     * 依据字符串获取Integer
     * @param integerStr
     * @return
     */
    public static Integer getInteger(String integerStr) {
    	try {
    		return Integer.valueOf(integerStr);
    	} catch (Exception e) {
    		return 0;
    	}
    }
    
	/**
	 * 获取map参数中参数并转化为BigDecimal
	 * @param map
	 * @param key
	 * @return
	 */
	public static Integer getInteger(Map<String,Object> map, String key) {
		try {
			return map.get(key) == null ? 0 : Integer.valueOf(map.get(key).toString());
		} catch (Exception e) {
			return 0;
		}
	}

	/**
	 * 获取
	 * @param val
	 * @param val2
	 * @return
	 */
	public static BigDecimal min(BigDecimal val, BigDecimal val2) {
		int res = compareTo(val, val2);
		if (res > 0) {
			return val2;
		} else  {
			return val;
		}
	}
	
	/**
	 * 拆分金额
	 * @param source
	 * @param divisor
	 * @return
	 */
	public static List<BigDecimal> splitBigDecimal(BigDecimal source, BigDecimal divisor) {
		List<BigDecimal> list = new ArrayList<>();
		if (isZero(source) || isZero(divisor) || source.compareTo(divisor) <= 0) {
			list.add(source);
			return list;
		}
		divisor = divisor.abs();
		// 取整
		BigDecimal ints = source.divideToIntegralValue(divisor).abs();
		// 取正负号
		BigDecimal signum = new BigDecimal(source.signum());
		for (int i = 0; i < ints.intValue(); i++) {
			list.add(divisor.multiply(signum));
		}
		// 取余数
		BigDecimal remain = source.remainder(divisor);
		if (!isZero(remain)) {
			list.add(remain);
		}
		// 校验累加是否等于总金额
		BigDecimal total = BigDecimal.ZERO;
		for (BigDecimal big : list) {
			total = total.add(big);
		}
		if (source.compareTo(total) != 0) {
			return Collections.emptyList();
		}
		return list;
	}
}
